# -*- coding: utf-8 -*-
"""
@Time ： 2024/12/9 14:59
@Auth ： 周瑞东 Ryan.Zhou
@File ：hal_serial.py
"""
import time
import threading
import serial
import serial.tools.list_ports
from utils.global_state import GlobalState
import RPi.GPIO as GPIO
from hal.plantower_example import aqi_settings
# from hal.plantower_example import aqi_data_parser


class HALPlantower9103:
    _instance = None

    def __new__(cls):
        """确保只有一个串口实例"""
        if cls._instance is None:
            cls._instance = super(HALPlantower9103, cls).__new__(cls)
            cls._instance.serial_port_handler = None
            cls._instance.__global_state = GlobalState()
        return cls._instance

    def __init__(self):
        if not hasattr(self, '_initialized'):  # 确保只初始化一次
            # self.pin = 3

            # GPIO.setmode(GPIO.BCM) # set up BCM GPIO numbering 
            # GPIO.cleanup(self.pin)
            # GPIO.setwarnings(False)
            # GPIO.setup(self.pin, GPIO.OUT, initial=GPIO.HIGH)
            self.debug = True
            self.conn_serial_port()

            self._initialized = True

    def conn_serial_port(self):
        #if debug: print aqi_settings.PT_SERIAL_PORT
        self.ser = serial.Serial(
            port=aqi_settings.PT_SERIAL_PORT,
            baudrate=aqi_settings.PT_BAUDRATE,
            parity=serial.PARITY_NONE,
            bytesize=serial.EIGHTBITS,
            stopbits=serial.STOPBITS_ONE,
            xonxoff=False,
            timeout=3.0
        )
        self.ser.inWaiting()
        print("conn ok")

    def vertify_G5data(self, data):
    	# if debug: print data
        n = 2
        check_sum_computed = int('42',16)+int('4d',16)
        for i in range(0, len(data)-4, n):
            # if debug: print (len(data))
            # if debug: print data[i:i+n]
            check_sum_computed=check_sum_computed+int(data[i:i+n],16)

        #check_sum_computed = sum(int(data[0:30],16))
        # get low 16 bit
        #check_sum_computed = check_sum_computed & 0xffff
        #versum = int(data[60]+data[61]+data[62]+data[63],16)
        versum = int(data[56]+data[57]+data[58]+data[59],16)
        # if debug: print check_sum_computed
        # if debug: print versum
        if check_sum_computed == versum:
            print( "data correct")
            return True
        else:
            print("data check failed")
            return False

    def read_G5data(self, data):
        # data = self.serial.read(22)
        # data_hex=data.encode('hex')

        data_hex = data.hex()

        if  False == self.vertify_G5data(data_hex): 
            return None

        # data_hex[0]表示串口接收到的数据中的其中1个十六进制数，即4个2进制位

        frameLength=int(data_hex[0]+data_hex[1]+data_hex[2]+data_hex[3],16)
        pm1_cf=int(data_hex[4]+data_hex[5]+data_hex[6]+data_hex[7],16)
        pm25_cf=int(data_hex[8]+data_hex[9]+data_hex[10]+data_hex[11],16)
        pm10_cf=int(data_hex[12]+data_hex[13]+data_hex[14]+data_hex[15],16)
        pm1=int(data_hex[16]+data_hex[17]+data_hex[18]+data_hex[19],16)
        pm25=int(data_hex[20]+data_hex[21]+data_hex[22]+data_hex[23],16)
        pm10=int(data_hex[24]+data_hex[25]+data_hex[26]+data_hex[27],16)
        diam_0_3_UM=int(data_hex[28]+data_hex[29]+data_hex[30]+data_hex[31],16)
        diam_0_5_UM = int(data_hex[32]+data_hex[33]+data_hex[34]+data_hex[35],16)
        diam_1_0_UM = int(data_hex[36]+data_hex[37]+data_hex[38]+data_hex[39],16)
        diam_2_5_UM = int(data_hex[40]+data_hex[41]+data_hex[42]+data_hex[43],16)
        diam_5_0_UM = int(data_hex[44]+data_hex[45]+data_hex[46]+data_hex[47],16)
        diam_10_UM = int(data_hex[48]+data_hex[49]+data_hex[50]+data_hex[51],16)
        # if debug: print "length: "+str(frameLength)
        # if debug: print "pm1_cf: "+str(pm1_cf)
        # if debug: print "pm25_cf: "+str(pm25_cf)
        # if debug: print "pm10_cf: "+str(pm10_cf)
        # if debug: print "pm1: "+str(pm1)
        if self.debug: 
            print("pm25: "+str(pm25))
        # if debug: print "pm10: "+str(pm10)
            print("diam_0_3_UM: "+str(diam_0_3_UM)) 
            print("diam_0_5_UM: "+str(diam_0_5_UM)) 
            print("diam_1_0_UM: "+str(diam_1_0_UM)) 
            print("diam_2_5_UM: "+str(diam_2_5_UM)) 
            print("diam_5_0_UM: "+str(diam_5_0_UM))
            print("diam_10_UM: "+str(diam_10_UM))
        iaqi_data = [pm1_cf, pm25_cf,pm10_cf, pm1, pm25,pm10,diam_0_3_UM,diam_0_5_UM,diam_1_0_UM,diam_2_5_UM,diam_5_0_UM,diam_10_UM]
    	# self.serial.close()
        return iaqi_data

    def check_keyword(self,bufferlength):
        # if debug: print "check_keyword"
        for i in range(bufferlength):
            token = self.ser.read()
            #i=i+1
            token_hex=token.hex()
            if self.debug: 
                print("token_hex", token_hex) 
            if token_hex == '42':
                # if debug: print "get 42"
                token2 = self.ser.read()
                #i=i+1
                token2_hex=token2.hex()
                if self.debug: 
                    print("token2_hex", token2_hex) 
                if token2_hex == '4d':
                    # if debug: print "get 4d"
                    return True
                elif token2_hex == '00': # fixme
                    # if debug: print "get 00"
                    token3 = self.ser.read()
                    #i=i+1
                    token3_hex = token3.hex()
                    if token3_hex == '4d':
                        # if debug: print "get 4d"
                        return True
                    
    def getAirQuality(self):
        bufferLength = self.ser.inWaiting()
        if self.debug:
            print(f"=====length=== \n {bufferLength}") 
        if bufferLength >= 3:
            try:
                print("ent check")
                if self.check_keyword(bufferLength):
                    print("quit check")
                    data = self.ser.read(30)
                    # print("data:", data)
                    # if debug: print data
                    airQuality = self.read_G5data(data)
                    return airQuality
            except:
                print("exception in getAirQuality")
                self.ser.close()
                self.conn_serial_port()
                return None
        return None